package aladyn.generator;

import java.io.ObjectInputStream.GetField;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;

import aladyn.exceptions.LRGenerationException;
import javassist.*;

/**
 * G��n��rateur de code des m��thodes "serialize" ou "deserialize"
 * @author Administrator YiHan Wang, Qi Xu, Bo CAI
 */
public class LRSerializableGenerator {
	
	/**
	 * Le loader de classe de Javassist.
	 */
	public static final ClassPool pool = ClassPool.getDefault();
	
	/**
	 * Le nom complet de l'interface LRSerializable
	 */
	public static final String serializeInterfaceName = "aladyn.interfaces.LRSerializable";
	
	/**
	 * Le nom de la m��thode serialize de l'interface LRSerializable
	 */
	public static final String serializeMethodName = "serialize";
	
	/**
	 * Le nom de la m��thode deserialize de l'interface LRSerializable
	 */
	public static final String deserializeMethodName = "deserialize";
	
	/**
	 * Le d��limiteur utilis�� dans la serialisation
	 */
	public static final String delimiter = "\"@\"";
	
	/**
	 * La chaine qui represente le pointer null dans la serialisation
	 */
	public static final String serializedNull = "\"null\"";
	
	public static final String outputDir = "bin";
	
	protected static HashMap<String, Integer> hashTab = new HashMap<String, Integer>();
	
	protected static int classNumero = 0;
	
	/**
	 * Charger une class a partir d'un fichier .class
	 * @param classPath Chemin du fichier .class �� charger
	 * @return CtClass de Javassist
	 * @throws NotFoundException
	 */
	public static CtClass LoadCtClass(String classPath) 
	throws NotFoundException {
		return pool.get(classPath);	
	}
	
	public static void addLRSerializable(String className) throws LRGenerationException{
		
		try {
			CtClass clazz = LoadCtClass(className);
			addLRSerializableInterface(clazz);
		} catch (NotFoundException e) {
			throw new LRGenerationException(e.getMessage());
		}
	}
	
	/**
	 * Ajouter l'interface "LRSerializable", ensuite g��n��rer et ajouter les m��thodes de cette interface
	 */
	public static void addLRSerializableInterface(CtClass clazz) 
	throws LRGenerationException{
		if(clazz == null) 
			throw new LRGenerationException("Null pointer argument.");
		// String.isInterface() -> true ??? why
		if(clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() 
		   || clazz.isEnum() || clazz.isAnnotation())
			throw new LRGenerationException("Not a class." + clazz.isInterface());
		
		try {			
			CtClass ctLRSerialisableInterface = pool.get(serializeInterfaceName);
			if(clazz.subtypeOf(ctLRSerialisableInterface)
				&& hashTab.get(clazz.getName()) != null)
				return;
			
			// ajout de l'interface
			clazz.addInterface(ctLRSerialisableInterface);
			
			// g��n��ration des m��thodes
			generateSerializeMethod(clazz);
			generateDeserializeMethodStringTokenizer(clazz);
			generateDeserializeMethodString(clazz);
			generateDeserializeMethodStringStringTokenizer(clazz);
			clazz.writeFile(outputDir);									// a revoir
			clazz.defrost();
		} catch (Exception e){	// NotFoundException, CannotCompileException
			throw new LRGenerationException(e.toString() + "\n" + e.getMessage());
		}
				
	}

	/**
	 * G��n��ration de code de la methode "serialize()" de l'interface "LRSerializable".
	 */
	public static CtMethod generateSerializeMethod(CtClass clazz) 
	throws LRGenerationException{
		if(clazz == null) 
			throw new LRGenerationException("Null pointer argument.");
		
		// code g��n��r��
		StringBuffer code;
		// le nom de la variable qui contient la chaine s��rialis�� dans la m��thode g��n��r��e "serialize()"
		String serializedStringName = "serialized";
		
		CtMethod serializeMethod;
		try {
			serializeMethod = clazz.getDeclaredMethod(serializeMethodName, new CtClass[0]);
		} catch (NotFoundException e1) {
			throw new LRGenerationException(e1.getMessage());
		}
		
		/* public String Serialize(){
		 * 		String serializedStringName = new String();
		 */
		code = new StringBuffer("{\n");
		code.append("\tString " + serializedStringName + " = new String();\n");
		
		code.append(generateSerializeObject("this", clazz, serializedStringName));
		
		/* 		return serializedStringName; 
		 * }
		 */
		code.append("\treturn " + serializedStringName + ";\n");
		code.append("}\n");

		System.out.println(clazz.getName());
		System.out.println(code.toString());		// !!! a supprimer

		try {
			serializeMethod.setBody(code.toString());
			//method = CtMethod.make(code.toString(), clazz);
		} catch (CannotCompileException e) {
			throw new LRGenerationException(e.getMessage());
		}
		return serializeMethod;
	}
	
	/**
	 * G��n��rer la partie de code pour s��rialiser l'objet
	 * @param objName Le nom de l'objet �� s��rialiser
	 * @param objType Le type de l'objet �� s��rialiser
	 * @param serializedStringName Le nom de la chaine de l'objet s��rialis�� dans la m��thode g��n��r��e "serialize()"
	 * @return Le code produit
	 * @throws LRGenerationException
	 */
	protected static String generateSerializeObject(String objName, CtClass objType, String serializedStringName) throws LRGenerationException{
		int myClassNumero = getNextClassNumero();
		Integer i = hashTab.put(objType.getName(), myClassNumero);
		System.out.println("!!!!!!!!!!! + " + i);
		
		/* serialized += objType.getName; */
		StringBuffer code = new StringBuffer("\t" + serializedStringName + " += \"" +  myClassNumero + "\";\n");
		// s��rialisation de tous les champs
		CtField[] fields = objType.getFields();
		try{
			for(CtField field : fields){
				// on ne serialise uniquement les champs non "final"
				if(!Modifier.isFinal(field.getModifiers()))
					code.append(generateSerializeField(field.getName(), field.getType(), serializedStringName, 1));
			}
		}catch(NotFoundException e){
			throw new LRGenerationException(e.getMessage());
		}
		return code.toString();
	}
	
	/**
	 * G��n��rer la partie de code pour s��rialiser un champs d'objet
	 * @param name Le nom du champs de l'objet 
	 * @param type Le type le champs de l'objet 
	 * @param serializedStringName Le nom de la chaine de l'objet s��rialis�� dans la m��thode g��n��r��e "serialize()"
	 * @param nbTabulations Le nombre de tabulations �� mettre devant chaque ligne de code, sans effet sur le r��sulat 
	 * @return Le code produit
	 * @throws LRGenerationException
	 */
	protected static String generateSerializeField(String fieldName, CtClass fieldType, 
		String serializedStringName, int nbTabulations) throws LRGenerationException{
				
		// si c'est un champs primitif
		if(fieldType.isPrimitive())
			/* serialized += "@" + name; */
			return generateSerializePrimitiveField(fieldName, fieldType, serializedStringName, nbTabulations);
			//return "\t" + serializedStringName + " += " + delimiter + " + " + name + ";\n";
		
		// tableau ou object
		if(fieldType.isArray())
			try{
				return generateSerializeArrayField(fieldName, fieldType.getComponentType(), serializedStringName, nbTabulations);
			} catch (NotFoundException e) {
				throw new LRGenerationException(e.getMessage());
			}
		else	// object
			return generateSerializeObjectField(fieldName, fieldType, serializedStringName, nbTabulations);
			
	}
	
	/**
	 * G��n��rer la partie de code pour s��rialiser un champs de type primitif
	 * @param primitiveName Le nom du champs
	 * @param Type Le type du champs
	 * @param serializedStringName Le nom de la chaine de l'objet s��rialis�� dans la m��thode g��n��r��e "serialize()"
	 * @param nbTabulations Le nombre de tabulations �� mettre devant chaque ligne de code, sans effet sur le r��sulat 
	 * @return Le code produit
	 * @throws LRGenerationException
	 */
	protected static String generateSerializePrimitiveField(String primitiveName, CtClass Type, String serializedStringName, int nbTabulations) throws LRGenerationException{
		String tabulations = generateTabulations(nbTabulations);
		return tabulations + serializedStringName + " += " + delimiter + " + " + primitiveName + ";\n";
	}		
	
	/**
	 * G��n��rer la partie de code pour s��rialiser un champs de type tableau d'objet
	 * @param arrayName Le nom du champs
	 * @param eltType Le type du champs
	 * @param serializedStringName Le nom de la chaine de l'objet s��rialis�� dans la m��thode g��n��r��e "serialize()"
	 * @param nbTabulations Le nombre de tabulations �� mettre devant chaque ligne de code, sans effet sur le r��sulat 
	 * @return Le code produit
	 * @throws LRGenerationException
	 */
	protected static String generateSerializeArrayField(String arrayName, CtClass eltType, String serializedStringName, int nbTabulations) throws LRGenerationException{
		String tabulations = generateTabulations(nbTabulations);
		
		/*	serialized += '@' + \"eltType.getName()\";
		 *  if(arrayName == null){
		 *  	serialized += "@" + "null";
		 *  }else{
		 *  	serialized += "@" + arrayName.length;
		 */
		StringBuffer code = new StringBuffer(tabulations + serializedStringName + " += " + delimiter + " + \""+ eltType.getName() + "\";\n");
		code.append(tabulations + "if(" + arrayName + " == null){\n");
		code.append(tabulations + "\t" + serializedStringName + " += " + delimiter + " + " + serializedNull + ";\n");
		code.append(tabulations + "}else{\n");
		code.append(tabulations + "\t" + serializedStringName + " += " + delimiter + " + " + arrayName + ".length;\n");

		// le nom �� donner aux ��l��ments du tableau dans le code g��n��r��
		String eltName = arrayName + "Elt";
		
		//	!!! la syntaxe suivante n'est pas support��e
		//	for(eltType.geName() eltName : arrayName){ 
		
		/*		eltType.getName eltName;
		 *		for(int i; i < arrayName.length; i++){
		 * 			eltName = arrayName[i];
		 */
		code.append(tabulations + "\t" + eltType.getName() + " " + eltName + ";\n"); 
		code.append(tabulations + "\tfor(int i = 0; i < " + arrayName + ".length ; i++){\n");
		code.append(tabulations + "\t\t" + eltName + " = " + arrayName + "[i];\n"); 

		code.append(generateSerializeField(eltName, eltType, serializedStringName, nbTabulations + 2));
		
		/* 		}
		 * }
		 */
		code.append(tabulations + "\t}\n");	// for
		code.append(tabulations + "}\n");	// else
		return code.toString();
	}
	
	/**
	 * G��n��rer la partie de code pour s��rialiser un champs de type objet d'objet
	 * @param objName Le nom du champs
	 * @param objType Le type du champs
	 * @param serializedStringName Le nom de la chaine de l'objet s��rialis�� dans la m��thode g��n��r��e "serialize()"
	 * @param nbTabulations Le nombre de tabulations �� mettre devant chaque ligne de code, sans effet sur le r��sulat 
	 * @return Le code produit
	 * @throws LRGenerationException
	 */
	protected static String generateSerializeObjectField(String objName, CtClass objType, String serializedStringName, int nbTabulations) throws LRGenerationException{
		String tabulations = generateTabulations(nbTabulations);
		StringBuffer code = new StringBuffer();
		
		// ajout de l'interface, si objType implemente deja cette interface, 
		// l'insertion de methode ne sera pas fait de nouveau
		addLRSerializableInterface(objType);
		
		/* if(objName == null)
		 * 		serialized += "@" + "null";
		 * else
		 * 		serialized += "@" + obj.serialize();
		 */
		code.append(tabulations + "if(" + objName + " == null)\n");
		code.append(tabulations + "\t" + serializedStringName + " += " + delimiter + " + " + serializedNull + ";\n");
		code.append(tabulations + "else\n");
		code.append(tabulations + "\t" + serializedStringName + " += " + delimiter + " + " + objName + "." + serializeMethodName + "();\n");
		return code.toString();
	}
	
	/**
	 * G��n��rer des tabulations
	 * @param nb Le nombre de tabulations �� g��n��rer
	 * @return Tabulations
	 */
	protected static String generateTabulations(int nb){
		String tabulations = "";
		for(int i = 0; i < nb; i++)
			tabulations += '\t';
		return tabulations;
	}
	
	/**
	 * g��n��ration de code de la methode "deserialize()" de l'interface "LRSerializable".
	 * @throws LRGenerationException 
	 */
	public static CtMethod generateDeserializeMethodStringTokenizer(CtClass clazz) throws LRGenerationException{
		if(clazz == null) 
			throw new LRGenerationException("Null pointer argument.");
		
		// code g��n��r��
		StringBuffer code;
		// le nom de la variable qui contient la chaine s��rialis�� dans la m��thode g��n��r��e "serialize()"
		String deserializedObjectName = "deserializedObject";
		// le nom de la variable qui contient le StringTokenizer
		String tokenizerName = "tokenizer";
		
		CtMethod deserializeMethod;
		try {
			CtClass ctString = LoadCtClass("java.lang.String");
			deserializeMethod = clazz.getDeclaredMethod(deserializeMethodName, new CtClass[]{ctString});
		} catch (NotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		/* public Object deserialize(StringTokenizer tokenizer){ */
		code = new StringBuffer("public static Object " + deserializeMethodName + "(java.util.StringTokenizer " + tokenizerName + "){\n");

		code.append(generateDeserializeObject(deserializedObjectName, clazz, tokenizerName));
		
		/* 		return deserializedObject; 
		 * }
		 */
		code.append("\treturn " + deserializedObjectName + ";\n");
		code.append("}\n");

		System.out.println(clazz.getName());
		System.out.println(code.toString());		// !!! a supprimer
		CtMethod method = null;
		try {
			method = CtMethod.make(code.toString(), clazz);
		} catch (CannotCompileException e) {
			throw new LRGenerationException(e.getMessage());
		}
		return method;
	}
	
	///protected static String generateDeserializeObject(String objName, CtClass objType, String serializedStringName) 
	protected static String generateDeserializeObject(String objName, CtClass objType, String tokenizerName)
	throws LRGenerationException{
		StringBuffer code = new StringBuffer();
		
		// v��rifications
		/* if(tokenizerName == null)
		 * 		return null;
		 */
		code.append("\tif(" + tokenizerName + " == null)\n");
		code.append("\t\treturn null;\n");

		String objTypeClassNumeroName = "objTypeClassNumero";
		/* String objTypeClassNumero;
		 * if(!tokenizer.hasMoreToken())
		 * 		return null;
		 * objTypeClassNumero = tokenizer.nextToken();
		 */
		code.append("\tString " + objTypeClassNumeroName + ";\n");
		code.append(generateDeserializeNextToken(tokenizerName, objTypeClassNumeroName, 1));

		//String serializedTypeName = 
		
		// a revoir ici; if((objTypeName != "null") && (objTypeName == ClassName)) ???
		/* if(1 != Integer.parseInt(objTypeClassNumero))
		 * 		return null;
		 */
		code.append("\tif(" + hashTab.get(objType.getName()) + " != Integer.parseInt(" 
					+ objTypeClassNumeroName + "))\n");
		code.append("\t\treturn null;\n");
		
		// instantiation
		/* objName = new instance(); 
		 */
		code.append(generateInstanceCode(objName, objType, 1));
		
		// s��rialisation des champs
		try{
			for(CtField field : objType.getFields()){
				// on ne serialise uniquement les champs non "final"
				if(!Modifier.isFinal(field.getModifiers()))
					code.append(generateDeserializeField(objName + "." + field.getName(), field.getType(), tokenizerName, 1));
			}
		}catch(NotFoundException e){
			throw new LRGenerationException(e.getMessage());
		}
		return code.toString();
	}
	
	protected static String generateDeserializeObject(String objName, CtClass objType, String objTypeName, String tokenizerName)
	throws LRGenerationException{
		StringBuffer code = new StringBuffer();
		
		// v��rifications
		/* if(tokenizerName == null || objTypeName == null)
		 * 		return null;
		 */
		code.append("\tif(" + tokenizerName + " == null || " + objTypeName + " == null)\n");
		code.append("\t\treturn null;\n");

		/// on n'a pas besoin de rev��rifier parceque la v��rification se fait au niveau au dessus
		/* if(!objType.getName().equals(objTypeName))
		 * 		return null;
		 */
		// code.append("\tif(!\"" + objType.getName() + "\".equals(" + objTypeName + "))\n");
		// code.append("\t\treturn null;\n");
		///
		
		// instantiation
		/* objName = new instance(); 
		 */
		code.append(generateInstanceCode(objName, objType, 1));
		
		// s��rialisation des champs
		try{
			for(CtField field : objType.getFields()){
				// on ne serialise uniquement les champs non "final"
				if(!Modifier.isFinal(field.getModifiers()))
					code.append(generateDeserializeField(objName + "." + field.getName(), field.getType(), tokenizerName, 1));
			}
		}catch(NotFoundException e){
			throw new LRGenerationException(e.getMessage());
		}
		return code.toString();
	}
		
	protected static String generateDeserializeField(String fieldName, CtClass fieldType,  
			String tokenizerName, int nbTabulations) throws LRGenerationException{
		if(fieldType.isPrimitive()){	// primitive
			return generateDeserializePrimitiveField(fieldName, fieldType, tokenizerName, nbTabulations);
		}else if(fieldType.isArray()){	// array
			try{
				return generateDeserializeArrayField(fieldName, fieldType.getComponentType(), tokenizerName, nbTabulations);
			} catch (NotFoundException e) {
				throw new LRGenerationException(e.getMessage());
			}
		}else{							// object
			return generateDeserializeObjectField(fieldName, fieldType, tokenizerName, nbTabulations);
		}
	}
	
	protected static String generateDeserializePrimitiveField(String fieldName, CtClass fieldType, 
			String tokenizerName, int nbTabulations){
		StringBuffer code = new StringBuffer();
		String tabulations = generateTabulations(nbTabulations);
		String serializedValueName = "serializedValue";
		
		/* String serializedValue;
		 * if(!tokenizer.hasMoreToken())
		 * 		return null;
		 * serializedValue = tokenizer.nextToken();
		 */
		code.append(tabulations + "String " + serializedValueName + ";\n");
		code.append(generateDeserializeNextToken(tokenizerName, serializedValueName, nbTabulations));
		
		/* type fieldName = value */
		code.append(tabulations + fieldName + " = ");
		if(fieldType == CtClass.booleanType)
			code.append("Boolean.parseBoolean(" + serializedValueName + ");\n");
		else if(fieldType == CtClass.byteType)
			code.append("Byte.parseByte(" + serializedValueName + ");\n");
		else if(fieldType == CtClass.charType)
			code.append(serializedValueName + ".charAt(0);\n");
		else if(fieldType == CtClass.doubleType)
			code.append("Double.parseDouble(" + serializedValueName + ");\n");
		else if(fieldType == CtClass.floatType)
			code.append("Float.parseFloat(" + serializedValueName + ");\n");
		else if(fieldType == CtClass.intType)
			code.append("Integer.parseInt(" + serializedValueName + ");\n");
		else if(fieldType == CtClass.longType)
			code.append("Long.parseLong(" + serializedValueName + ");\n");
		else if(fieldType == CtClass.shortType)
			code.append("Short.parseShort(" + serializedValueName + ");\n");
//		else if(fieldType == CtClass.voidType)
//			code.append("void");
//		else error
		
		return code.toString(); 
	}
	
	protected static String generateDeserializeArrayField(String arrayName, CtClass eltType, 
			String tokenizerName, int nbTabulations) throws LRGenerationException{
		StringBuffer code = new StringBuffer();
		String tabulations = generateTabulations(nbTabulations);
		String serializedEltTypeName = "serializedEltType";			// extrait de la objet serialis��
		String eltTypeName = eltType.getName();						// type attendu
		String dataName = "data";									// le token juste apr��s le type, il peut ��tre null ou length
		String lengthName = "length";
		String eltName = "elt";
		
		// v��rification de type
		/* String serializedEltType;
		 * if(!tokenizer.hasMoreToken())
		 * 		return null;
		 * serializedEltType = tokenizer.nextToken();
		 */
		code.append(tabulations + "String " + serializedEltTypeName + ";\n");
		code.append(generateDeserializeNextToken(tokenizerName, serializedEltTypeName, nbTabulations));
		
		/* if(!eltTypeName.equals(serializedEltTypeName))
		 * 		return null;
		 */
		code.append(tabulations + "if(!\"" + eltTypeName + "\".equals(" + serializedEltTypeName + "))\n");
		code.append(tabulations + "\treturn null;\n");
		
		// v��rification null ou length
		/* String data = new String();
		 * if(!tokenizer.hasMoreToken())
		 * 		return null;
		 * data = tokenizer.nextToken();
		 */
		code.append(tabulations + "String " + dataName + " = new String();\n");
		code.append(generateDeserializeNextToken(tokenizerName, dataName, nbTabulations));
		
		/* if("null".equals(data))
		 * 		array = null;
		 * else{
		 * 		int length = Integer.valueOf(data).intValue;	// exception
		 * 		EltType elt;
		 * 		for(int i = 0; i < length; i++){
		 */
		code.append(tabulations + "if(" + serializedNull + ".equals(" + dataName + ")){\n");
		code.append(tabulations + "\t" + arrayName + " = null;\n");
		code.append(tabulations + "}else{\n");
		code.append(tabulations + "\tint " + lengthName + " = Integer.parseInt(" + dataName + ");\n");
		code.append(tabulations + "\t" + eltTypeName + " " + eltName + ";\n");
		code.append(tabulations + "\tfor(int i = 0; i < " + lengthName + "; i++){\n");
		
		//generate
		////code.append(generateDeserializeField(eltName, eltType, instanceName, tokenizerName, nbTabulations))

		code.append(generateDeserializeField(eltName, eltType, tokenizerName, nbTabulations + 2));
		code.append(tabulations + "\t}\n");
		code.append(tabulations + "}\n");
	
		return code.toString();
	}
	
	protected static String generateDeserializeObjectField(String objName, CtClass objType, 
			String tokenizerName, int nbTabulations) {
		String tabulations = generateTabulations(nbTabulations);
		return tabulations + objName + " = " + objType.getName() + "." + deserializeMethodName + "(" + tokenizerName + ");\n";
	}
	
	protected static String generateDeserializeNextToken(String tokenizerName, String varName, int nbTabulations){
		/* if(!tokenizer.hasMoreToken())
		 * 		return null;
		 * varName = tokenizer.nextToken();
		 */
		String tabulations = generateTabulations(nbTabulations);
		return tabulations + "if(!" + tokenizerName + ".hasMoreTokens())\n"
			+ tabulations + "\treturn null;\n"
			+ tabulations + varName + " = " + tokenizerName + ".nextToken();\n";
	}
	
	protected static String generateInstanceCode(String instanceName, CtClass type, int nbTabulations) throws LRGenerationException{
		String booleanDefaultValue = "false";
		String charDefaultValue = "\'a\'";
		String numericDefaultValue = "0";
		String objectDefaultVale = "null";
		
		try{
			StringBuffer code = new StringBuffer();
			String tabulations = generateTabulations(nbTabulations);
			String typeName = type.getName();
			
			/* Type instance = new type( */
			code.append(tabulations + typeName + " " + instanceName + " = new " + typeName + "(");
			
			CtConstructor[] constructors = type.getConstructors();
			if(constructors.length != 0){	// il y a au moins un constructeur d��clar��
				CtConstructor constructor = type.getConstructors()[0];
				CtClass[] paramTab = constructor.getParameterTypes();
				
				CtClass param;
				for(int i = 0; i < paramTab.length; i++){
					param = paramTab[i];
					if(i != 0)
						code.append(", ");
					
					if(param.isPrimitive()){
						if(param == CtClass.booleanType) 	// boolean
							code.append(booleanDefaultValue);
						else if(param == CtClass.charType)	// char
							code.append(charDefaultValue);
						else								// char, int, float, double...
							code.append(numericDefaultValue);
					}else{		// array, object
						code.append("(" + param.getName() + ")" + objectDefaultVale);
					}				
				}
			} // si aucun constructeur, on peut appeler le constructeur par d��faut sans argument
			code.append(");\n");
			return code.toString();
		}catch(NotFoundException e){
			throw new LRGenerationException(e.getMessage());
		}
	}
	
	public static CtMethod generateDeserializeMethodString(CtClass clazz) throws LRGenerationException{
		if(clazz == null) 
			throw new LRGenerationException("Null pointer argument.");
		
		// code g��n��r��
		StringBuffer code;
		// l'objet serialis��
		String serializedStringName = "serialized";
		
		String tokenizerName = "tokenizer";
		
		String tabulations = "\t";

		
		/* public Object deserialize(String str){
		 */
		code = new StringBuffer("public static Object " + deserializeMethodName + "(String " + serializedStringName + "){\n");

		/* if(serialized == null || serialized.equals("null"))
		 * 		return null;
		 * StringTokenizer tokenizer = new StringTokenizer(serialized, delimiter);
		 * return deserialized(tokenizer);
		 */
		code.append(tabulations + "if(" + serializedStringName + " == null || " 
					+ serializedStringName + ".equals(\"null\"))\n");
		code.append(tabulations + "\t" + "return null;\n");
		code.append(tabulations + "java.util.StringTokenizer " + tokenizerName + " = new java.util.StringTokenizer("
					+ serializedStringName + ", " + delimiter + ");\n");
		code.append(tabulations + "return " + deserializeMethodName + "(" + tokenizerName + ");\n");
		code.append("}\n");
		
		System.out.println(clazz.getName());
		System.out.println(code.toString());		// !!! a supprimer
		CtMethod method = null;
		try {
			method = CtMethod.make(code.toString(), clazz);
		} catch (CannotCompileException e) {
			throw new LRGenerationException(e.getMessage());
		}
		return method;
	}
	
	
	public static CtMethod generateDeserializeMethodStringStringTokenizer(CtClass clazz) 
	throws LRGenerationException{
		if(clazz == null) 
			throw new LRGenerationException("Null pointer argument.");
		
		// code g��n��r��
		StringBuffer code;
		// le type de l'objet serialis��(ex : Point, ou 1 dans le cas d'optimisation)
		String serializedType = "type";
		// le nom de la variable qui contient la chaine s��rialis�� dans la m��thode g��n��r��e "serialize()"
		String deserializedObjectName = "deserializedObject";
		// le nom de la variable qui contient le StringTokenizer
		String tokenizerName = "tokenizer";
		
		/* public Object deserialize(String type, StringTokenizer tokenizer){
		 */
		code = new StringBuffer("public static Object " + deserializeMethodName 
				+ "(String " + serializedType + ", java.util.StringTokenizer " + tokenizerName + "){\n");

		code.append(generateDeserializeObject(deserializedObjectName, clazz, serializedType, tokenizerName));
		
		/* 		return deserializedObject; 
		 * }
		 */
		code.append("\treturn " + deserializedObjectName + ";\n");
		code.append("}\n");

		System.out.println(clazz.getName());
		System.out.println(code.toString());		// !!! a supprimer
		CtMethod method = null;
		try {
			method = CtMethod.make(code.toString(), clazz);
		} catch (CannotCompileException e) {
			throw new LRGenerationException(e.getMessage());
		}
		return method;
	}
	
	
	
	public static final String typeMethodName = "type";

	/**
	 * Le nom complet de la class Dispatcher
	 */
	public static final String dispatcherName = "aladyn.dispatcher.Dispatcher";
	
	
	
	public static void generateTypeMethodString(ArrayList<String> classes) 
	throws LRGenerationException {
		CtClass dispatcher;
		try {
			dispatcher = LoadCtClass("aladyn.dispatcher.Dispatcher");
		} catch (NotFoundException e) {
			throw new LRGenerationException(e.getMessage());
		}
		
		StringBuffer code = new StringBuffer("");
		String tabulation = "\t";
		String arg1 = "$1";
		// le nom de la variable qui contient le StringTokenizer
		String tokenizerName = "tokenizer";
		String serializedTypeName = "serializedType";
		
		/* 	{
		 * 		StringTokenizer tokenizer = new StringTokenizer($1, "@");
		 * 		String type;
		 */
		code.append("{\n");
		code.append(tabulation + "java.util.StringTokenizer " + tokenizerName +
					" = new java.util.StringTokenizer(" + arg1 + ", " + delimiter + ");\n");
		code.append(tabulation + "String " + serializedTypeName + ";\n");
		
		/* 		type = tokenizer.nextToken();
		 */
		code.append(generateDeserializeNextToken(tokenizerName, serializedTypeName, 1));
		
		/* 		return type(type, tokenizer);
		 *	}
		 */
		code.append(tabulation + "return " + typeMethodName + "(" + serializedTypeName
					+ ", " + tokenizerName + ");\n");
		code.append("}\n");
		System.out.println(code.toString());
		CtMethod method;
		try {
			CtClass ctString = LoadCtClass("java.lang.String");
			CtClass[] params = {ctString};
			method = dispatcher.getDeclaredMethod(typeMethodName, params);
			method.setBody(code.toString());
			dispatcher.writeFile(outputDir);
			dispatcher.defrost();
		} catch (Exception e) {		// NotFoundException, CanNotCompileException, IOException
			throw new LRGenerationException(e.getMessage());
		}
	}
	
	
	public static void generateTypeMethodStringStringTokenizer(ArrayList<String> classes) 
	throws LRGenerationException {
		CtClass dispatcher;
		try {
			dispatcher = LoadCtClass("aladyn.dispatcher.Dispatcher");
		} catch (NotFoundException e) {
			throw new LRGenerationException(e.getMessage());
		}
		
		StringBuffer code = new StringBuffer("");
		String tabulation = "\t";
		// le nom de la variable qui contient le StringTokenizer
		String serializedTypeName = "$1";
		String tokenizerName = "$2";
		
		/* {
		 * 	 if("Point".equals(type)
		 *     return Point.deserialize(type, tokenizer);
		 */
		code.append("{\n");
		for(String className : classes){
			System.out.println(className + hashTab.containsKey(className) + "!!!!!!!!!!!!");
			code.append(tabulation + "if(" + hashTab.get(className) + " == " 
						+ "Integer.parseInt(" + serializedTypeName + "))\n");
			code.append(tabulation + "\treturn " + className + ".deserialize(" 
						+ serializedTypeName + ", " + tokenizerName + ");\n");
		}
		
		// class non trouvée
		/* return null;
		 */
		code.append(tabulation + "return null;\n");
		code.append("}\n");
		System.out.println(code.toString());
		CtMethod method;
		try {
			CtClass ctString = LoadCtClass("java.lang.String");
			CtClass ctStringTokenizer = LoadCtClass("java.util.StringTokenizer");
			CtClass[] params = {ctString, ctStringTokenizer};
			method = dispatcher.getDeclaredMethod(typeMethodName, params);
			
			method.setBody(code.toString());
			dispatcher.writeFile(outputDir);
			dispatcher.defrost();
		} catch (Exception e) {		// NotFoundException, CanNotCompileException, IOException
			throw new LRGenerationException(e.getMessage());
		}
	}
	
	protected static int getNextClassNumero(){
		return classNumero++;
	}
	
	
}
		
		
		
		
		
		
		